package sde.actor;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;

public class RealTimeBE extends ControlMachine {
	
	private static class TimerComparator implements Comparator<Timer> {
		public int compare(Timer t1, Timer t2) {
			if (t1.firetime() < t2.firetime())
				return -1;
			if (t1.firetime() > t2.firetime())
				return +1;
			if (t1 != t2) {
				if (Math.random() < 0.5)
					return -1;
				return +1;
			}
			return 0;
		}
	}

	private PriorityQueue<Timer> TQ = new PriorityQueue<Timer>(1000,
			new TimerComparator());
	private LinkedList<Message> MQ = new LinkedList<Message>();

	private MessagesInformation mi = new MessagesInformation();
	private int oldstatus;
	private Message dispatch;
	private boolean isImmediateMessage=false;
	private double current;
	private long last;
	private Object lock = new Object();
	
	public RealTimeBE() {
		Actor.setRuntime( this );
		Timer.setRuntime(this);
		current = 0;
		last = System.currentTimeMillis();
	}
	
	public double now(){
		  synchronized( lock ){
			  long currentTime=System.currentTimeMillis();
			  long elapsed = currentTime-last;
			  last = currentTime; current += elapsed;
			  return current;
		  }
	 }
	
	@Override
	public void schedule(Message m) {
		synchronized (lock) {
			if (m instanceof Timer) {
				Timer t = (Timer) m;
				TQ.remove(t);
				TQ.add(t);
			} else {
				MQ.add(m);
			}
		}
	}

	@Override
	public void unSchedule(Message m) {
		synchronized (lock) {
			if (m instanceof Timer) {
				Timer t = (Timer) m;
				TQ.remove(t);
			} else {
				MQ.remove(m);
			}
		}
	}

	@Override
	public void reset() {
		synchronized (lock) {
			TQ.clear();
			MQ.clear();
		}
	}

	@Override
	public void controller() {
		while( true ){//control loop
			Timer mit = null; // most imminent timer
			if (TQ.size() != 0) {
				// allow a timer to fire
				if (TQ.peek().firetime() <= now()) {
					synchronized (lock) {
						mit = TQ.poll();
					}
				}
			}
			if (mit != null || MQ.size() > 0) {
				if (mit != null) { // priority to fired timer
					dispatch = mit.timeout();
					mit = null;
				} else {
					if(TQ.peek() != null && mi.isAvailable(MQ.peek())){
						if(TQ.peek().firetime() <= now() + mi.get(MQ.peek())){
							continue;//ASPETTO CHE IL TIMEOUT SCATTI
						}
					}else{
						synchronized (lock) {
							dispatch = MQ.removeFirst();
							isImmediateMessage = true;
						}
					}
				}
				if(isImmediateMessage){
					mi.start(dispatch, now());//mi calcolo le statistiche
				}
				oldstatus = dispatch.receiver().currentStatus();
				dispatch.receiver().handler(dispatch);
				if (dispatch.receiver().currentStatus() != oldstatus) {
					// catenate DMQ events in front of MQ
					while (dispatch.receiver().DMQ.size() != 0) {
						synchronized (lock) {
							MQ.addFirst(dispatch.receiver().DMQ.removeLast());
						}
					}
				}// if
				if(isImmediateMessage){
					mi.stop(dispatch, now());
					isImmediateMessage=false;
				}
	         }//if - no dispatch message
	      }//while
	}
}
